package com.redxiii.spike;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.redxiii.spike.api.communication.CommunicationType;
import com.redxiii.spike.api.pmi.PmiType;
import com.redxiii.spike.engine.CoreSettings;
import com.redxiii.spike.pmi.commons.PmiSettings;
import com.redxiii.spike.pmi.commons.PmiSettings.DBType;
import com.redxiii.spike.pmi.redmine.RedmineHandler;
import com.redxiii.spike.pmi.trac.TracHandler;
import com.redxiii.spike.services.msn.MsnService;
import com.redxiii.spike.services.msn.MsnSettings;
import com.redxiii.spike.services.xmpp.XmppService;
import com.redxiii.spike.services.xmpp.XmppSettings;
import com.redxiii.spike.util.IMHandler;
import com.redxiii.spike.util.core.StorageSystem;
import com.redxiii.util.db.DBAccess;
import com.redxiii.util.db.MySqlDB;
import com.redxiii.util.db.PostgreSQLDB;
import com.redxiii.util.gui.InstallConfigGui;
import com.redxiii.util.gui.actions.AlertSystem;
import com.redxiii.util.gui.actions.NextAction;
import com.redxiii.util.gui.config.Frame;

public class InstallW {

	private static final Logger logger = LoggerFactory.getLogger(InstallW.class);
	private static Configuration config = new PropertiesConfiguration();
	
	private static Frame createGui() {
		Frame firstFrame = new Frame("Spike Instance ID", config);
		
		firstFrame
			.createField(Constraints.id.name(), "Id")
			.setAction(new NextAction() {
				@Override
				public boolean next(Frame frame, AlertSystem alertSystem) {
					logger.debug("Checking ID: {}", config.getProperty(Constraints.id.name()));
					if (config.containsKey(Constraints.id.name())) {
						return true;
					}
					return false;
				}
				@Override
				public String getProgressStatus() {
					return null;
				}
			});
		
		firstFrame
			.createNextFrame("Communication Service")
			.createField(Constraints.comService.name(), CommunicationType.class, "Service")
			.createField(Constraints.comLogin.name(), "Login")
			.createSecretField(Constraints.comPassword.name(), "Password")
			
			.createNextFrame("Project Management")
			.createField(Constraints.pmiType.name(), PmiType.class, "Type")
			.createField(Constraints.dbType.name(), DBType.class, "Database")
			.createField(Constraints.dbHost.name(), "Host")
			.createField(Constraints.dbSchema.name(), "Schema")
			.createField(Constraints.dbUser.name(), "User")
			.createSecretField(Constraints.dbPass.name(), "Password")
			.setAction(new NextAction() {
				@Override
				public boolean next(Frame frame, AlertSystem alertSystem) {
					
					if (testConnection()){
						return true;
					}
					
					alertSystem.alert("Unable do connect on database");
					return false;
				}
				
				@Override
				public String getProgressStatus() {
					return "Connecting...";
				}
			});
		
		return firstFrame;
	}
	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		
		Frame firstFrame = createGui();
		
		InstallConfigGui gui = new InstallConfigGui(firstFrame, "Spike Installation");
		
		gui.run();
		
		String instance = config.getString(Constraints.id.name());
		StorageSystem.init(instance);
		StorageSystem storage = StorageSystem.getInstance();
		CoreSettings coreSettings = storage.load(CoreSettings.class, null, true);
		
		// Project Management
		Map<String, Class<?>> handlerAlias = coreSettings.getHandlerAlias();
		handlerAlias.clear();
		handlerAlias.put("@Trac", TracHandler.class);
		handlerAlias.put("@Redmine", RedmineHandler.class);
		handlerAlias.put("@IM", IMHandler.class);
		
		coreSettings.setHandlerAlias(handlerAlias);
		
		// Project Management - AutoStart Handler
		Set<Class<?>> handlerAutoStart = coreSettings.getHandlerAutoStart();
		PmiType pmiType = (PmiType) config.getProperty(Constraints.pmiType.name());
		PmiSettings pmiSettings = storage.load(PmiSettings.class, pmiType.name(), true);
		switch(pmiType) {
			case Redmine:
				handlerAutoStart.add(RedmineHandler.class);
				break;
			case Trac:
				handlerAutoStart.add(TracHandler.class);
				break;
		}
		
		// Project Management - Database
		DBType dbType = (DBType) config.getProperty(Constraints.dbType.name());
		
		pmiSettings.setDbType(dbType);
		pmiSettings.setDbHost(config.getString(Constraints.dbHost.name()));
		pmiSettings.setDbName(config.getString(Constraints.dbSchema.name()));
		pmiSettings.setDbLogin(config.getString(Constraints.dbUser.name()));
		pmiSettings.setDbPassword(config.getString(Constraints.dbPass.name()));
		pmiSettings.setAutoLoginOnly(true);
		pmiSettings.getProperties().put("example", "1234");
		
		// Communication Servive
		CommunicationType comType = (CommunicationType) config.getProperty(Constraints.comService.name());
		switch(comType) {
			case MSN:
				coreSettings.setService(MsnService.class);
				MsnSettings msnSettings = storage.load(MsnSettings.class, comType.name().toLowerCase(), true);
				msnSettings.setLogin(config.getString(Constraints.comLogin.name()));
				msnSettings.setPassword(config.getString(Constraints.comPassword.name()));
				break;
			case XMPP:
				coreSettings.setService(XmppService.class);
				XmppSettings xmppSettings = storage.load(XmppSettings.class, comType.name().toLowerCase(), true);
				xmppSettings.setLogin(config.getString(Constraints.comLogin.name()));
				xmppSettings.setPassword(config.getString(Constraints.comPassword.name()));
				break;
		}
		
		storage.persist();
		
//		File root = new File("run.bat");
//		ProcessBuilder pBuilder = new ProcessBuilder(root.getAbsolutePath(),instance);
//		pBuilder.start();
	}

	
	private static boolean testConnection() {
		try {
			DBType dbType = (DBType) config.getProperty(Constraints.dbType.name());
			
			
			DBAccess dbAccess = null;
			switch(dbType) {
			case MySql:
				dbAccess = new MySqlDB(
						config.getString(Constraints.dbHost.name()),
						config.getString(Constraints.dbSchema.name()),
						config.getString(Constraints.dbUser.name()),
						config.getString(Constraints.dbPass.name()));
				break;
			case PosgreSql:
				dbAccess = new PostgreSQLDB(
						config.getString(Constraints.dbHost.name()),
						config.getString(Constraints.dbSchema.name()),
						config.getString(Constraints.dbUser.name()),
						config.getString(Constraints.dbPass.name()));
				break;
			}
			return dbAccess.testConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
}


enum Constraints {
	id,
	comService,
	comLogin,
	comPassword,
	pmiType,
	dbType,
	dbHost,
	dbSchema,
	dbUser,
	dbPass,
}